import requests
import hashlib
import time
import urllib.parse
from typing import Optional, Dict, List
import json
from collections import OrderedDict

class WritingOpenCorrectController:
    def __init__(self, cap_no):
        self.base_url = "https://open.ctedu.com.cn/open/isvc"
        self.app_key = "AEifXnSpBwp9nygX"
        self.app_secret = "kAsCwAC7QUZu9XWx9YddPcGrbwByxTuZ2WctTscRyh6bkTcrKEBTKGV2Uwr2CTeZ"
        # self.cap_no = "K1866371139455021057"  # 中文作文批改的接口唯一编码
        self.cap_no = cap_no
        self.sign_version = "1.0.0"
        self.rest_template = requests.Session()

    def correct(self, content: str, problem: str, grade: str, task: str) -> str:
        url = self.base_url
        # self.cap_no = "K1866371139455021057"  # 中文作文批改的接口唯一编码
        uuid = self.generate_uuid()
        timestamp = str(int(time.time() * 1000))
        base_param = {
            "appKey": self.app_key,
            "timestamp": timestamp,
            "uuid": uuid,
            "signVersion": self.sign_version,
            "capNo": self.cap_no
        }
        # print("base_param : ", base_param)
        url = self.init_url(url, base_param)
        sign = self.get_sign(self.app_key, self.app_secret, uuid, timestamp, url, base_param)
        url += f"&sign={sign}"
        print(url)

        param_map = {
            "content": content,
            "problem": problem,
            # 年级字段
            "grade": grade,
            # cn中文批阅 en-app 英文批阅
            "task": task
        }
        param = {
            "paramJson": json.dumps(param_map),
            "paramType": "3"
        }

        headers = {
            "Content-Type": "application/json;charset=utf-8"
        }

        result = ""
        try:
            response = self.rest_template.post(url, json=param, headers=headers)
            print("status code : ", response.status_code)
            # print(response.text)
            if response.status_code == 200 and response.text:
                result = response.text
                # print(f"请求url: {urllib.parse.quote(url)}, 请求参数为: {json.dumps(param, ensure_ascii=False)}, 请求头为: {json.dumps(headers)}, 响应结果为: {result}")
        except Exception as e:
            # print(f"请求url: {urllib.parse.quote(url)}, 请求参数为: {json.dumps(param)}, 请求头为: {json.dumps(headers)}, 异常原因: {e}")
            return result
        return result
    
    def recognize(self, imageUrl: str, name: str, task: str) -> str:
        url = self.base_url
        # self.cap_no = "K1823621972597166080"  # 中文作文批改的接口唯一编码
        uuid = self.generate_uuid()
        timestamp = str(int(time.time() * 1000))
        base_param = {
            "appKey": self.app_key,
            "timestamp": timestamp,
            "uuid": uuid,
            "signVersion": self.sign_version,
            "capNo": self.cap_no
        }
        url = self.init_url(url, base_param)
        sign = self.get_sign(self.app_key, self.app_secret, uuid, timestamp, url, base_param)
        url += f"&sign={sign}"
        # print(url)

        param_map = {
            "imageUrl": imageUrl,
            "paperFormat": "normal",
            "name": name,
            # cn中文批阅 en 英文批阅
            "task": task
        }
        param = {
            "paramJson": json.dumps(param_map),
            "paramType": "3"
        }

        headers = {
            "Content-Type": "application/json;charset=utf-8"
        }

        result = ""
        try:
            response = self.rest_template.post(url, json=param, headers=headers)
            print("status code : ", response.status_code)
            # print(response.text)
            if response.status_code == 200 and response.text:
                result = response.text
                # print(f"请求url: {urllib.parse.quote(url)}, 请求参数为: {json.dumps(param)}, 请求头为: {json.dumps(headers)}, 响应结果为: {result}")
        except Exception as e:
            # print(f"请求url: {urllib.parse.quote(url)}, 请求参数为: {json.dumps(param)}, 请求头为: {json.dumps(headers)}, 异常原因: {e}")
            return result
        return result

    @staticmethod
    def generate_uuid() -> str:
        import uuid
        return str(uuid.uuid4())

    @staticmethod
    def get_sign(app_key, app_secret, uuid, timestamp, url, url_params):
        try:
            params = OrderedDict()
            if '?' in url:
                query_params = url.split('?')[1]
                for param in query_params.split('&'):
                    key, value = param.split('=')
                    key = urllib.parse.unquote(key)
                    value = urllib.parse.unquote(value) if value else ""
                    if key == "sign":
                        continue
                    params[key] = value

            for key, value in url_params.items():
                if key == "sign":
                    continue
                params[key] = value if value else ""

            key_sort = sorted(params.keys())
            sign_salt = ''.join([f"{key}{params[key]}" for key in key_sort])
            sign_data = f"{app_key}{timestamp}{uuid}{app_secret}{sign_salt}"
            sign = hashlib.sha256(sign_data.encode('utf-8')).hexdigest()
            return sign
        except Exception as e:
            raise Exception("生成签名异常，检查参数URL是否正确!", e)

    @staticmethod
    def get_sha256(origin: str) -> str:
        try:
            sha256 = hashlib.sha256()
            sha256.update(origin.encode('utf-8'))
            return sha256.hexdigest()
        except Exception as e:
            raise Exception("找不到对应的加密算法.", e)

    @staticmethod
    def init_url(url: str, params: Optional[Dict[str, str]] = None) -> str:
        if params:
            query_params = "&".join(f"{key}={urllib.parse.quote(str(value))}" for key, value in params.items())
            if "?" in url:
                url += f"&{query_params}"
            else:
                url += f"?{query_params}"
        return url


if __name__ == "__main__":
    # 批改示例调用
    cap_no = "K1823621972601360384"
    controller = WritingOpenCorrectController(cap_no=cap_no)
    content = "有你相伴\n\n宛转岁月中,一抹璀璨的光晖揭开了黑夜,迎接黎明,温暖了我的整个童年。\n\n记忆中的爷爷无所不能:帮我修理自行车、机器猫、电子琴等根本不在话下;打开黄桃罐头更是轻而易举;小小的棋子在他手下更是过五关,斩六将”\n\n小城的秋雨犹如利剑,细丝如针的雨刺进的皮肤,凛冽的狂风更如狮兽般威风冲动。闹钟不知响了多少遍,伴着屋外灰灰蒙蒙的天气,暖烘烘的被窝让我欲罢不能。眼看去跳舞的时间已至,秒针一圈圈飞速转动,妈妈赶紧把我从被窝中拉出,我一揉眼的功夫,衣服已经放在旁边,拿好早餐,飞速下楼。爷爷在楼下的自行车旁等候我多时了,虽然他披着雨衣,但是他那瑟瑟发抖的身躯显然不会骗人。他把我抱上后座在这斜风细雨摇摇晃晃行驶,当我抬头望向他的后颈时,儿时的我以为他是被汗浸湿了,其实不然,那是针针细雨。\n\n他没有抱怨我的赖床,而是可我冷不冷,却不在意他湿漉漉的后背。\n\n五夏那年,他和奶奶一起带我去三亚,我们乘坐的是卧铺,爷爷有时去停站会买各各省份不同的特产。和前几次一样,他又去透气,熟练地跨上站台,他纵身一跃,消失在我的视线范围。奇怪的是,这次停靠的时间犹为短暂。一声鸣笛,没等大家反应过来,火车已经缓缓开动,窗边的风景又开始变化。可我一直没见到爷爷。我四处乱窜,不顾列车员的阻挠,奔走于节节车厢,在倒数第三节车厢,我一眼就锁定了那个手拿两个棒糖的他。“看,爷爷给你买的西瓜味棒棒糖,你最喜欢的。”我一手拿着棒棒糖打量,另一只手被他牵住“下次不许乱跑,多危险。”\n\n从懵懂无知到豆蔻年华,一路都有你的陪伴之所以一路呐喊,从不彷得,是因为爷爷相伴左右、\n\n"
    problem = "当你从懵懂走向明理，从稚嫩走向成熟，从依赖走向独立的时候，成长的历程会有许多让你感怀的事情，许多曾经让你感动的人物，还有陪伴过你的书籍音乐，甚至是角落里微不足道的一件玩具，都曾让你体味很多受益的哲理，这些，在你的人生经历上留下印痕的点点滴滴，如甘泉潘湿你成长的岁月，丰盈看你年轻的生命。请以《有你相伴》为题写一篇文章要求;2全文不少于 600 字，不要超出所给字格，不得出现真实的人名校名。"
    grade = ''
    task = 'cn'
    result = controller.correct(content, problem, grade, task)
    print("result : ", result)

    # # 识别示例
    # cap_no = "K1823621972597166080"
    # imageUrl = "https://yj-oss.yunxiao.com/v1/baidu-raw/8989575/12965/2/000214/0D0ACA55-3CE4-11EF-B316-6C4B9094B4C2.png?authorization=bce-auth-v1%2Fa908715249bb41c998c7d924b2476b37%2F2024-12-18T07%3A53%3A52Z%2F3600%2Fhost%2F4695ab167cb6f00e7aa6abe8963c4c2d5bd93c0c54f93494f0986802dae17bd7"
    # task = "cn"
    # name = "test.png"
    # controller = WritingOpenCorrectController(cap_no=cap_no)
    # result = controller.recognize(imageUrl, name, task)
    # print("result : ", result)



